#include <iostream>
#include "EquationSolver.h"
#define _USE_MATH_DEFINES
#include <cmath>
using namespace std;
/**
 * B
 */
double fun_1(double x)
{
    return 1 / x - tan(x);
}
double fun_2(double x)
{
    return 1 / x - pow(2, x);
}
double fun_3(double x)
{
    return pow(2, -1 * x) + pow(M_E, x) + 2 * cos(x) - 6;
}
double fun_4(double x)
{
    return (pow(x, 3) + 4 * pow(x, 2) + 3 * x + 5) / (2 * pow(x, 3) - 9 * pow(x, 2) + 18 * x - 2);
}

/**
 * C
 */
double fun_C(double x)
{
    return x - tan(x);
}
double diff_C(double x)
{
    return 1 - 1 / (cos(x) * cos(x));
}

/**
 * D
 */
double fun_d_1(double x)
{
    return sin(x / 2) - 1;
}
double fun_d_2(double x)
{
    return pow(M_E, x) - tan(x);
}
double fun_d_3(double x)
{
    return pow(x, 3) - 12 * x * x + 3 * x + 1;
}

/**
 * E
 */
double Equa(double h)
{
    return 10 * (0.5 * M_PI - asin(h) - h * pow(1 - h * h, 0.5)) - 12.4;
}
double Equa_diff(double h)
{
    return 10 * (-1 / pow(1 - h * h, 0.5) - pow(1 - h * h, 0.5) + 2 * h * h / pow(1 - h * h, 0.5));
}

/**
 * F
 */

double D = 55;
double Eq(double x)
{
    double l = 89;
    double h = 49;
    double beta1 = 11.5 * M_PI / 180;
    double A = l * sin(beta1);
    double B = l * cos(beta1);
    double C = (h + D / 2) * sin(beta1) - 0.5 * D * tan(beta1);
    double E = (h + D / 2) * cos(beta1) - 0.5 * D;

    return A * sin(x / 180 * M_PI) * cos(x / 180 * M_PI) + B * pow(sin(x / 180 * M_PI), 2) - C * cos(x / 180 * M_PI) - E * sin(x / 180 * M_PI);
}

double Eq_diff(double x)
{
    double l = 89;
    double h = 49;
    double beta1 = 11.5 * M_PI / 180;
    double A = l * sin(beta1);
    double B = l * cos(beta1);
    double C = (h + D / 2) * sin(beta1) - 0.5 * D * tan(beta1);
    double E = (h + D / 2) * cos(beta1) - 0.5 * D;

    return A * cos(2 * x / 180 * M_PI) + B * sin(2 * x / 180 * M_PI) + C * sin(x / 180 * M_PI) - E * cos(x / 180 * M_PI);
}

int main()
{

    double error;
    /**
     * B
     */
    cout << "----------------B--------------------" << endl;
    biesection a;
    a(0, 2 * M_PI, fun_1, 1e-6);
    if (a.solve())
    {
        error = fun_1(a.ans());
        cout << "1. root = " << a.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "1.Can't find the root." << endl;
    }

    a(0, 1, fun_2, 1e-6);
    if (a.solve())
    {
        error = fun_2(a.ans());
        cout << "2. root = " << a.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "2.Can't find the root." << endl;
    }

    a(1, 3, fun_3, 1e-5);
    a.set_M(300);
    if (a.solve())
    {
        error = fun_3(a.ans());
        cout << "3. root = " << a.ans() << "     f(root) =" << error << endl;
    }
    else
    {
        cout << "3.Can't find the root." << endl;
    }

    a(0, 4, fun_4);
    a.set_M(300); // 增加迭代次数，试图找出一个根
    if (a.solve())
    {
        error = fun_4(a.ans());
        cout << "4. root = " << a.ans() << "   f(root) =" << error << endl;
    }
    else
    {
        cout << "4.Can't find the root." << endl;
    }
    /**
     * C
     */
    cout << "----------------C--------------------" << endl;
    Newton b;
    b(fun_C, diff_C, 4.5);
    if (b.solve())
    {
        error = fun_C(b.ans());
        cout << "The root near 4.5 is " << b.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root near 4.5 ." << endl;
    }

    b(fun_C, diff_C, 7.7);
    if (b.solve())
    {
        error = fun_C(b.ans());
        cout << "The root near 7.7 is " << b.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root near 7.7 ." << endl;
    }

    /**
     * D
     */
    cout << "----------------D--------------------" << endl;
    cout << "            Given x_0,x_1" << endl;
    secant c;
    c(fun_d_1, 0, M_PI / 2);
    if (c.solve())
    {
        error = fun_d_1(c.ans());
        cout << "Root = " << c.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root." << endl;
    }

    c(fun_d_2, 1, 1.4);
    if (c.solve())
    {
        error = fun_d_2(c.ans());
        cout << "Root = " << c.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root." << endl;
    }

    c(fun_d_3, 0, -0.5);
    if (c.solve())
    {
        error = fun_d_3(c.ans());
        cout << "Root = " << c.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root." << endl;
    }

    cout << endl
         << "            Changed x_0,x_1" << endl;
    c(fun_d_1, 2, 1.1);
    if (c.solve())
    {
        error = fun_d_1(c.ans());
        cout << "Root = " << c.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root." << endl;
    }

    c(fun_d_2, 2, 2.4);
    if (c.solve())
    {
        error = fun_d_2(c.ans());
        cout << "Root = " << c.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root." << endl;
    }

    c(fun_d_3, 3, 6);
    if (c.solve())
    {
        error = fun_d_3(c.ans());
        cout << "Root = " << c.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root." << endl;
    }
    cout << "-----------------E-------------------" << endl;
    a(0, 1, Equa, 0.01);
    if (a.solve())
    {
        error = Equa(a.ans());
        cout << "biesection :  h = " << a.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root." << endl;
    }
    b(Equa, Equa_diff, 0.4, 0.01);
    if (a.solve())
    {
        error = Equa(a.ans());
        cout << "Newton's method :  h =" << a.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root." << endl;
    }
    c(Equa, 0.3, 0.4, 0.01);
    if (a.solve())
    {
        error = Equa(a.ans());
        cout << "secant :  h =" << a.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root." << endl;
    }

    /**
     * F
     */
    cout << "-----------------F-------------------" << endl;
    b(Eq, Eq_diff, 33);
    b.set_M(1000);
    if (b.solve())
    {
        error = Eq(b.ans());
        cout << "Newton's method :  solution =" << b.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root." << endl;
    }

    D = 30;
    b(Eq, Eq_diff, 33);
    b.set_M(1000);
    if (b.solve())
    {
        error = Eq(b.ans());
        cout << "Newton's method :  solution =" << b.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root." << endl;
    }

    // D=30;
    cout<<"x_0 =120,x_1 =123 :"<<endl;
    c(Eq, 120, 123);
    c.set_M(1000);
    if (c.solve())
    {
        error = Eq(c.ans());
        cout << "Secant method :  solution =" << c.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root." << endl;
    }
    cout<<"x_0 =1,x_1 =0 :"<<endl;
    c(Eq, 1, 0, 1e-6);
    c.set_M(1000);
    if (c.solve())
    {
        error = Eq(c.ans());
        cout << "Secant method :  solution =" << c.ans() << "    f(root) =" << error << endl;
    }
    else
    {
        cout << "Can't find the root." << endl;
    }

    return 0;
}